﻿using Quartz;
using Quartz.Impl;

namespace ApiTemplate.Application
{
    /// <summary>
    /// 调度任务应用服务
    /// </summary>
    public class SchedulerApplication : BaseApplication, ISchedulerApplication
    {
        /// <summary>
        /// 调度任务数据访问层
        /// </summary>
        public ISchedulerTaskDAL SchedulerTaskDAL { get; set; }

        /// <summary>
        /// 日志数据访问层
        /// </summary>
        public ISchedulerTaskLogDAL SchedulerTaskLogDAL { get; set; }

        /// <summary>
        /// 调度工厂
        /// </summary>
        public StdSchedulerFactory StdSchedulerFactory { get; set; }


        /// <summary>
        /// 添加一个定时任务
        /// </summary>
        /// <param name="input">添加定时任务的入参</param>
        /// <returns>是否添加成功</returns>
        public async Task<bool> AddAsync(AddSchedulerTaskInput input)
        {
            input.CreatedTime = DateTime.Now;
            string taskId = await SchedulerTaskDAL.AddAsync(input);
            IScheduler _scheduler = await StdSchedulerFactory.GetScheduler();
            ExtendJobFactory extendJobFactory = new(SchedulerTaskDAL, SchedulerTaskLogDAL);
            _scheduler.JobFactory = extendJobFactory;
            await _scheduler.Start();
            IJobDetail job = JobBuilder.Create<HttpJob>()
                    .WithIdentity(new JobKey(taskId))
                    .Build();

            job.JobDataMap.Add("input", input);//添加参数
            job.JobDataMap.Add("taskId", taskId);//添加参数

            ITrigger trigger = TriggerBuilder.Create()
                    .WithIdentity(taskId)
                    .StartNow()
                    .WithCronSchedule(input.CronStr)
                    .Build();
            await _scheduler.ScheduleJob(job, trigger);
            return true;
        }

        /// <summary>
        /// 修改定时任务
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<bool> UpdateAsync(UpdateSchedulerTaskInput input)
        {
            //先删除
            IScheduler _scheduler = await StdSchedulerFactory.GetScheduler();
            ExtendJobFactory extendJobFactory = new(SchedulerTaskDAL, SchedulerTaskLogDAL);
            _scheduler.JobFactory = extendJobFactory;
            var entity = await SchedulerTaskDAL.GetAsync(input.Id);
            await _scheduler.DeleteJob(new JobKey(input.Id));
            await SchedulerTaskDAL.DeleteAsync(new BaseGuidListInput { Ids = new List<string> { input.Id } });

            //重新添加
            AddSchedulerTaskInput addSchedulerTaskInput = new()
            {
                CronStr = input.CronStr,
                Parameter = input.Parameter,
                RequsetType = input.RequsetType,
                TaskName = input.TaskName,
                Url = input.Url,
                CreatedTime = entity.CreatedTime,
                LastExecTime = entity.LastExecTime
            };
            string taskId = await SchedulerTaskDAL.AddAsync(addSchedulerTaskInput);
            //原来的日志修改为新加的
            await SchedulerTaskLogDAL.UpdateSchedulerTaskLogByTaskIdAsync(input.Id, taskId);

            await _scheduler.Start();
            IJobDetail job = JobBuilder.Create<HttpJob>()
                    .WithIdentity(new JobKey(taskId))
                    .Build();



            job.JobDataMap.Add("input", addSchedulerTaskInput);//添加参数
            job.JobDataMap.Add("taskId", taskId);//添加参数

            ITrigger trigger = TriggerBuilder.Create()
                    .WithIdentity(taskId)
                    .StartNow()
                    .WithCronSchedule(input.CronStr)
                    .Build();
            await _scheduler.ScheduleJob(job, trigger);

            return true;
        }

        /// <summary>
        /// 获取单个定时任务
        /// </summary>
        /// <param name="id">任务id</param>
        /// <returns></returns>
        public async Task<GetSchedulerTaskOutput> GetAsync(string id)
        {
            return await SchedulerTaskDAL.GetAsync(id);
        }

        /// <summary>
        /// 暂停任务
        /// </summary>
        /// <param name="input">要操作的任务id集合</param>
        /// <returns></returns>
        public async Task<bool> PauseTask(BaseGuidListInput input)
        {
            foreach (var id in input.Ids)
            {
                IScheduler _scheduler = await StdSchedulerFactory.GetScheduler();
                var entity = await SchedulerTaskDAL.GetAsync(id);
                if (entity == null)
                {
                    throw new BusinessException
                    {
                        Code = ErrorCode.DataDeleted,
                        ErrorMessage = "调度任务不存在"
                    };
                }
                else
                {
                    await _scheduler.PauseJob(new JobKey(id));
                }
            }

            await SchedulerTaskDAL.PauseTaskAsync(input);
            return true;
        }

        /// <summary>
        /// 恢复任务
        /// </summary>
        /// <param name="input">要操作的任务id集合</param>
        /// <returns></returns>
        public async Task<bool> RenewTaskAsync(BaseGuidListInput input)
        {
            foreach (string id in input.Ids)
            {
                IScheduler _scheduler = await StdSchedulerFactory.GetScheduler();
                var entity = await SchedulerTaskDAL.GetAsync(id);
                if (await _scheduler.CheckExists(new JobKey(id)))
                {
                    await _scheduler.ResumeJob(new JobKey(id));
                }
                else
                {

                    if (entity == null)
                    {
                        throw new BusinessException
                        {
                            Code = ErrorCode.DataDeleted,
                            ErrorMessage = "任务已被删除"
                        };
                    }
                    else
                    {
                        AddSchedulerTaskInput addTaskInput = new AddSchedulerTaskInput
                        {
                            CronStr = entity.CronStr,
                            Parameter = entity.Parameter,
                            RequsetType = entity.RequsetType,
                            TaskName = entity.TaskName,
                            Url = entity.Url
                        };
                        await _scheduler.Start();
                        IJobDetail job = JobBuilder.Create<HttpJob>()
                                .WithIdentity(new JobKey(id))
                                .Build();

                        job.JobDataMap.Add("input", addTaskInput);//添加参数
                        job.JobDataMap.Add("taskId", id);//添加参数

                        ITrigger trigger = TriggerBuilder.Create()
                                .WithIdentity(id)
                                .StartNow()
                                .WithCronSchedule(addTaskInput.CronStr)
                                .Build();
                        await _scheduler.ScheduleJob(job, trigger);
                    }
                }
            }

            await SchedulerTaskDAL.RenewTaskAsync(input);
            return true;
        }

        /// <summary>
        /// 删除任务
        /// </summary>
        /// <param name="input">要操作的任务id集合</param>
        /// <returns></returns>
        public async Task<bool> DeleteAsync(BaseGuidListInput input)
        {
            foreach (string item in input.Ids)
            {
                IScheduler _scheduler = await StdSchedulerFactory.GetScheduler();
                ExtendJobFactory extendJobFactory = new(SchedulerTaskDAL, SchedulerTaskLogDAL);
                _scheduler.JobFactory = extendJobFactory;
                await _scheduler.DeleteJob(new JobKey(item));
            }

            await SchedulerTaskDAL.DeleteAsync(input);
            return true;
        }

        /// <summary>
        /// 获取定时任务列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PageResult<GetSchedulerTaskPageOutput>> GetPageResultAsync(GetSchedulerTaskPageInput input)
        {
            return await SchedulerTaskDAL.GetPageResultAsync(input);
        }

        /// <summary>
        /// 获取指定任务的执行日志
        /// </summary>
        /// <param name="taskId">任务id</param>
        /// <returns></returns>
        public async Task<List<SchedulerTaskLog>> GetTaskLogAsync(string taskId)
        {
            return await SchedulerTaskLogDAL.GetTaskLogAsync(taskId);
        }


        /// <summary>
        /// 初始化调度任务
        /// </summary>
        public void InitSchedulerTask()
        {
            //获取数据库中所有的调度任务
            List<GetSchedulerTaskOutput> list = SchedulerTaskDAL.GetAllSchedulerTaskList();
            foreach (var item in list)
            {
                StdSchedulerFactory factory = new();

                IScheduler _scheduler = factory.GetScheduler().Result;
                //job中需要使用到数据访问层，这里自定义实现
                ExtendJobFactory myJobFactory = new(SchedulerTaskDAL, SchedulerTaskLogDAL);
                _scheduler.JobFactory = myJobFactory;
                _scheduler.Start().Wait();

                //创建job
                IJobDetail job = JobBuilder.Create<HttpJob>()
                        .WithIdentity(new JobKey(item.Id))
                        .Build();

                AddSchedulerTaskInput input = new()
                {
                    CronStr = item.CronStr,
                    Parameter = item.Parameter,
                    RequsetType = item.RequsetType,
                    Url = item.Url,
                    TaskName = item.TaskName
                };
                job.JobDataMap.Add("input", input);//添加参数
                job.JobDataMap.Add("taskId", item.Id);//添加参数

                //立即执行
                ITrigger trigger = TriggerBuilder.Create()
                        .WithIdentity(item.Id)
                        .StartNow()
                        .WithCronSchedule(input.CronStr)
                        .Build();
                _scheduler.ScheduleJob(job, trigger).Wait();
            }
        }
    }
}
